-
Notifications
You must be signed in to change notification settings - Fork 1
feat: 팝업창 구현 #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: 팝업창 구현 #31
The head ref may contain hidden characters: "\uC628\uBCF4\uB529-\uD31D\uC5C5\uCC3D"
Conversation
fragment_friend_list.xml 에서 button 생성 후 팝업창 뜨는 것 확인 목적으로 리사이클러뷰 재배치함 필요시 돌려놓으면 됩니다)
Walkthrough
Sequence Diagram(s)sequenceDiagram
participant User as 사용자
participant Frag as FriendListTabFragment
participant VM as FriendListViewModel
participant Adapter as FriendListAdapter
participant Popup as Popup
User->>Frag: newInstance(position)로 프래그먼트 생성/열기
Frag->>Frag: onCreateView()에서 binding 초기화 및 반환
Frag->>VM: 친구/요청 리스트 관찰 등록
VM-->>Frag: 리스트 데이터 (nullable)
Frag->>Adapter: initFriendList/initRequestList(데이터 또는 emptyList)
Frag->>Frag: layout_empty 보이기/숨기기 결정
User->>Frag: 빈 화면에서 btn_block 클릭
Frag->>Popup: showPopup(textList, left, right)
Popup-->>Frag: rightClickFunction()/leftClickFunction()
Frag->>User: Toast 표시
sequenceDiagram
participant User as 사용자
participant RV as ChatRoomParticipantRVAdapter
participant Popup as PopupWindow
participant Dialog as BlockDialog(Activity)
User->>RV: 참가자 항목의 '차단' 선택
RV->>Popup: 기존 팝업 dismiss()
RV->>Dialog: inflate R.layout.dialog_block -> AlertDialog 생성/표시
User->>Dialog: 체크박스/입력 후 제출 또는 취소
Dialog-->>RV: (없음/로컬 처리) — 제출 시 후속 동작 수행(패치에 이벤트 바인딩 없음)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🧹 Nitpick comments (4)
app/src/main/java/umc/onairmate/ui/friend/list/FriendListTabFragment.kt (4)
78-82: initData에서 user를 먼저 로드하도록 순서 조정 권장이후의 로직(특히 삭제 결과 처리)에서
user.userId를 사용하므로, 네트워크 호출 전에 user를 초기화하는 편이 안전합니다.private fun initData() { - if (type == LIST_TYPE) viewModel.getFriendList() - if (type == REQUEST_TYPE) viewModel.getRequestedFriendList() - user = SharedPrefUtil.getData("user_info") ?: UserData() + user = SharedPrefUtil.getData("user_info") ?: UserData() + if (type == LIST_TYPE) viewModel.getFriendList() + if (type == REQUEST_TYPE) viewModel.getRequestedFriendList() }
121-121: 빈 구현 제거 또는 TODO 명시
clickCollection이 빈 블록입니다. detekt가 경고한 대로 제거하거나, 향후 구현이 필요하다면 TODO를 명시하세요.
139-140: context 대신 requireContext 사용 권장Fragment의
context는 null일 수 있습니다.requireContext()를 사용해 NPE를 방지하세요.- binding.rvFriendList.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + binding.rvFriendList.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
25-25: 사소한 스타일: 불필요한 빈 생성자 괄호 제거 가능
class FriendListTabFragment : Fragment()로 간단히 표현할 수 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these settings in your CodeRabbit configuration.
📒 Files selected for processing (2)
app/src/main/java/umc/onairmate/ui/friend/list/FriendListTabFragment.kt(4 hunks)app/src/main/res/layout/fragment_friend_list_tab.xml(3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
app/src/main/java/umc/onairmate/ui/friend/list/FriendListTabFragment.kt (2)
app/src/main/java/umc/onairmate/ui/friend/search/SearchUserRVAdapter.kt (1)
initData(52-56)app/src/main/java/umc/onairmate/ui/home/room/RoomRVAdapter.kt (1)
initData(70-87)
🪛 detekt (1.23.8)
app/src/main/java/umc/onairmate/ui/friend/list/FriendListTabFragment.kt
[warning] 121-121: This empty block of code can be removed.
(detekt.empty-blocks.EmptyFunctionBlock)
| viewModel.result.observe(viewLifecycleOwner, Observer { message -> | ||
| if (message == null) return@Observer | ||
| if (message == "친구가 삭제되었습니다.") friendChatViewModel.deleteFriend(friendId,user.userId) | ||
| message ?: return@Observer | ||
| if (message == "친구가 삭제되었습니다.") friendChatViewModel.deleteFriend(friendId, user.userId) | ||
| initData() | ||
| Toast.makeText(requireContext(),message, Toast.LENGTH_SHORT).show() | ||
| Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show() | ||
| viewModel.clearResult() | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
문자열 비교 기반 로직은 취약하며 userId=0 가드 필요
- 서버/VM 메시지와 한글 문자열을 직접 비교하면 다국어/문구 변경에 취약합니다. 결과는 code/sealed class 등으로 분기하세요.
user.userId가 기본값 0일 수 있어 잘못된 삭제 동기화 호출 위험이 있습니다. 가드를 추가하세요.
예시 수정(문자열 리소스로 이전 + userId 가드):
- if (message == "친구가 삭제되었습니다.") friendChatViewModel.deleteFriend(friendId, user.userId)
+ if (message == getString(R.string.friend_deleted)) {
+ if (user.userId != 0) {
+ friendChatViewModel.deleteFriend(friendId, user.userId)
+ }
+ }strings.xml(파일 외 추가):
<resources>
<string name="friend_deleted">친구가 삭제되었습니다.</string>
</resources>또는 더 바람직하게는 viewModel.result를 sealed class Result { object FriendDeleted : Result ... } 형태로 바꿔 타입 안정적으로 분기해 주세요. 변경 원하시면 제안 드리겠습니다.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== repo root: ==="
pwd
echo
echo "=== Find FriendListTabFragment file ==="
rg --hidden -n "FriendListTabFragment" || true
echo
echo "=== Print FriendListTabFragment (first 400 lines) if exists ==="
if [ -f "app/src/main/java/umc/onairmate/ui/friend/list/FriendListTabFragment.kt" ]; then
sed -n '1,400p' app/src/main/java/umc/onairmate/ui/friend/list/FriendListTabFragment.kt || true
else
echo "File not found at expected path."
fi
echo
echo "=== Search for viewModel.result, deleteFriend, userId, and User model ==="
rg --hidden -n "viewModel.result" || true
rg --hidden -n "deleteFriend" || true
rg --hidden -n "friendChatViewModel" || true
rg --hidden -n "data class .*User|class .*User" || true
rg --hidden -n "userId" || trueLength of output: 17676
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== FriendViewModel.kt ==="
if [ -f "app/src/main/java/umc/onairmate/ui/friend/FriendViewModel.kt" ]; then
sed -n '1,400p' app/src/main/java/umc/onairmate/ui/friend/FriendViewModel.kt
else
echo "FriendViewModel.kt not found"
fi
echo
echo "=== FriendChatViewModel.kt ==="
if [ -f "app/src/main/java/umc/onairmate/ui/friend/chat/FriendChatViewModel.kt" ]; then
sed -n '1,400p' app/src/main/java/umc/onairmate/ui/friend/chat/FriendChatViewModel.kt
else
echo "FriendChatViewModel.kt not found"
fi
echo
echo "=== SharedPrefUtil.kt ==="
if [ -f "app/src/main/java/umc/onairmate/ui/util/SharedPrefUtil.kt" ]; then
sed -n '1,400p' app/src/main/java/umc/onairmate/ui/util/SharedPrefUtil.kt
else
rg --hidden -n "object SharedPrefUtil|class SharedPrefUtil" || true
fi
echo
echo "=== UserData.kt ==="
if [ -f "app/src/main/java/umc/onairmate/data/model/entity/UserData.kt" ]; then
sed -n '1,200p' app/src/main/java/umc/onairmate/data/model/entity/UserData.kt
else
echo "UserData.kt not found"
fi
echo
echo "=== Search for literal message '친구가 삭제되었습니다.' ==="
rg --hidden -n "친구가 삭제되었습니다." || true
echo
echo "=== Search for LiveData result in FriendViewModel ==="
rg --hidden -n "val result" app/src/main/java/umc/onairmate/ui/friend || true
rg --hidden -n "MutableLiveData.*result|MutableLiveData<.*>.*result" || trueLength of output: 15434
친구 삭제 분기: 문자열 비교 취약 및 userId=0 가드 필요
간단히: viewModel.result가 문자열("친구가 삭제되었습니다.")로 분기되고 있으며, SharedPref에서 유저를 못 불러오면 user.userId가 기본값 0이 되어 잘못된 소켓 호출을 할 수 있습니다. 수정이 필요합니다.
수정이 필요한 위치:
- app/src/main/java/umc/onairmate/ui/friend/list/FriendListTabFragment.kt — viewModel.result.observe 내부 (현재 message == "친구가 삭제되었습니다.")
- app/src/main/java/umc/onairmate/ui/friend/search/SearchFriendTabFragment.kt — viewModel.result 관찰부(유사한 패턴)
- app/src/main/java/umc/onairmate/ui/friend/FriendViewModel.kt — _result: MutableLiveData<String?> (문자열 메시지 전달 방식 자체)
권장 최소 수정 예시(간단 패치):
- viewModel.result.observe(viewLifecycleOwner, Observer { message ->
- message ?: return@Observer
- if (message == "친구가 삭제되었습니다.") friendChatViewModel.deleteFriend(friendId, user.userId)
- initData()
- Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
- viewModel.clearResult()
- })
+ viewModel.result.observe(viewLifecycleOwner, Observer { message ->
+ message ?: return@Observer
+ // 문자열 리터럴 대신 리소스(또는 더 나은 타입)를 사용하고 userId 가드 추가
+ if (message == getString(R.string.friend_deleted)) {
+ if (user.userId != 0) {
+ friendChatViewModel.deleteFriend(friendId, user.userId)
+ }
+ }
+ initData()
+ Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
+ viewModel.clearResult()
+ })strings.xml(추가):
<string name="friend_deleted">친구가 삭제되었습니다.</string>더 권장되는 개선(우선순위):
- FriendViewModel.result를 문자열이 아닌 sealed class / enum / 상태 코드 형태로 변경(Result.FriendDeleted 등).
- UI는 메시지(Toast)와 별개로 결과 타입을 보고 소켓 호출 등 후속 작업을 수행.
- 위 변경을 SearchFriendTabFragment 등 모든 관찰부에 적용.
태그:
🤖 Prompt for AI Agents
In app/src/main/java/umc/onairmate/ui/friend/list/FriendListTabFragment.kt
around lines 97-103, the observer currently compares viewModel.result to a raw
string and calls friendChatViewModel.deleteFriend with user.userId that may be
0; change the branching to use a typed result (preferably a sealed class/enum
like Result.FriendDeleted or at minimum compare against a string resource
R.string.friend_deleted) and add a guard to only call
friendChatViewModel.deleteFriend when user.userId is valid (non-zero); also
apply the same pattern to
app/src/main/java/umc/onairmate/ui/friend/search/SearchFriendTabFragment.kt and
refactor FriendViewModel._result from MutableLiveData<String?> to a typed result
LiveData so UI reacts to result types (Toast can still display localized string
resources).
| override fun acceptRequest(data: RequestedFriendData) { | ||
| val text = data.nickname+"님의 친구요청을 수락하시겠습니까?" | ||
| val textList = listOf(text,"수락","거절") | ||
| showPopup( | ||
| text =textList, | ||
| left = { viewModel.acceptFriend(data.userId, "REJECT") }, | ||
| right = { viewModel.acceptFriend(data.userId, "ACCEPT")} ) | ||
| val textList = listOf("${data.nickname}님의 친구요청을 수락하시겠습니까?", "수락", "거절") | ||
| showPopup(textList, | ||
| left = { viewModel.acceptFriend(data.userId, "REJECT") }, | ||
| right = { viewModel.acceptFriend(data.userId, "ACCEPT") }) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수락/거절 라벨과 동작이 반대로 매핑된 것으로 보입니다
textList는 ["수락","거절"]로 라벨링하는데, left는 REJECT, right는 ACCEPT 실행입니다. TwoButtonPopup이 [메시지, left 라벨, right 라벨] 순서를 사용한다면, 현재 구성은 사용자가 “수락”을 눌러도 거절이 수행되는 UX 오류가 됩니다.
라벨과 동작을 맞추도록 하나를 정정하세요. 예시(라벨 순서를 “거절”, “수락”으로 교체):
- val textList = listOf("${data.nickname}님의 친구요청을 수락하시겠습니까?", "수락", "거절")
+ val textList = listOf("${data.nickname}님의 친구요청을 수락하시겠습니까?", "거절", "수락")
showPopup(textList,
- left = { viewModel.acceptFriend(data.userId, "REJECT") },
- right = { viewModel.acceptFriend(data.userId, "ACCEPT") })
+ left = { viewModel.acceptFriend(data.userId, "REJECT") },
+ right = { viewModel.acceptFriend(data.userId, "ACCEPT") })또는 라벨은 유지하고 left/right 동작을 서로 바꾸는 방식으로 수정해도 됩니다.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| override fun acceptRequest(data: RequestedFriendData) { | |
| val text = data.nickname+"님의 친구요청을 수락하시겠습니까?" | |
| val textList = listOf(text,"수락","거절") | |
| showPopup( | |
| text =textList, | |
| left = { viewModel.acceptFriend(data.userId, "REJECT") }, | |
| right = { viewModel.acceptFriend(data.userId, "ACCEPT")} ) | |
| val textList = listOf("${data.nickname}님의 친구요청을 수락하시겠습니까?", "수락", "거절") | |
| showPopup(textList, | |
| left = { viewModel.acceptFriend(data.userId, "REJECT") }, | |
| right = { viewModel.acceptFriend(data.userId, "ACCEPT") }) | |
| } | |
| override fun acceptRequest(data: RequestedFriendData) { | |
| val textList = listOf("${data.nickname}님의 친구요청을 수락하시겠습니까?", "거절", "수락") | |
| showPopup(textList, | |
| left = { viewModel.acceptFriend(data.userId, "REJECT") }, | |
| right = { viewModel.acceptFriend(data.userId, "ACCEPT") }) | |
| } |
🤖 Prompt for AI Agents
In app/src/main/java/umc/onairmate/ui/friend/list/FriendListTabFragment.kt
around lines 114 to 119, the popup button labels and their actions are reversed:
the textList labels imply left="수락" right="거절" but left currently calls REJECT
and right calls ACCEPT; fix by making labels and handlers match — either swap
the textList order to ["거절", "수락"] so left=REJECT right=ACCEPT stays correct, or
keep textList as ["수락", "거절"] and swap the left/right lambdas so left calls
ACCEPT and right calls REJECT.
| private fun showPopup(text: List<String>, right: () -> Unit?, left: () -> Unit?) { | ||
| val dialog = TwoButtonPopup(text, object : PopupClick { | ||
| override fun rightClickFunction() { right() } | ||
| override fun leftClickFunction() { | ||
| left() | ||
| } | ||
| }, false) // 뒤로 가기 막고 싶으면 false 넣어주세요, 아니면 생략가능합니다. | ||
| override fun leftClickFunction() { left() } | ||
| }, false) | ||
| dialog.show(activity?.supportFragmentManager!!, "FriendPopup") | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NPE 위험과 불필요한 nullable 람다 — childFragmentManager 사용 및 타입 정교화
activity?.supportFragmentManager!!는 lifecycle 타이밍에 따라 NPE 위험이 있습니다. Fragment에서 DialogFragment를 띄울 때는 childFragmentManager(또는 parentFragmentManager)를 사용하세요. 또한 콜백은 nullable일 필요가 없습니다.
- private fun showPopup(text: List<String>, right: () -> Unit?, left: () -> Unit?) {
+ private fun showPopup(text: List<String>, right: () -> Unit, left: () -> Unit) {
val dialog = TwoButtonPopup(text, object : PopupClick {
override fun rightClickFunction() { right() }
override fun leftClickFunction() { left() }
}, false)
- dialog.show(activity?.supportFragmentManager!!, "FriendPopup")
+ dialog.show(childFragmentManager, "FriendPopup")
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private fun showPopup(text: List<String>, right: () -> Unit?, left: () -> Unit?) { | |
| val dialog = TwoButtonPopup(text, object : PopupClick { | |
| override fun rightClickFunction() { right() } | |
| override fun leftClickFunction() { | |
| left() | |
| } | |
| }, false) // 뒤로 가기 막고 싶으면 false 넣어주세요, 아니면 생략가능합니다. | |
| override fun leftClickFunction() { left() } | |
| }, false) | |
| dialog.show(activity?.supportFragmentManager!!, "FriendPopup") | |
| } | |
| private fun showPopup(text: List<String>, right: () -> Unit, left: () -> Unit) { | |
| val dialog = TwoButtonPopup(text, object : PopupClick { | |
| override fun rightClickFunction() { right() } | |
| override fun leftClickFunction() { left() } | |
| }, false) | |
| dialog.show(childFragmentManager, "FriendPopup") | |
| } |
🤖 Prompt for AI Agents
In app/src/main/java/umc/onairmate/ui/friend/list/FriendListTabFragment.kt
around lines 142 to 148, replace the risky use of
activity?.supportFragmentManager!! and nullable lambda types: change the
function signature to accept non-null callbacks (right: () -> Unit, left: () ->
Unit), update the PopupClick implementation to call those non-null lambdas
directly, and show the dialog with childFragmentManager (or
parentFragmentManager if appropriate) instead of force-unwrapping activity; this
removes the NPE risk and unnecessary nullable types.
| // btn_block 클릭 시 popup 생성 | ||
| private fun setBindings() { | ||
| // 빈 화면 버튼이 보일 때만 작동 | ||
| binding.btnBlock.setOnClickListener { | ||
| val nickname = "친구" // 빈 화면 상태용 닉네임 | ||
| val textList = listOf("$nickname 님을 차단하시겠습니까?", "예", "아니오") | ||
| showPopup(textList, | ||
| left = { | ||
| Toast.makeText( | ||
| requireContext(), | ||
| "$nickname 님을 차단했습니다.", | ||
| Toast.LENGTH_SHORT | ||
| ).show() | ||
| }, | ||
| right = { | ||
| Toast.makeText(requireContext(), "차단 취소", Toast.LENGTH_SHORT).show() | ||
| }) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
팝업 문구 하드코딩 — 문자열 리소스화 및 문구 일관성
"예"/"아니오", "차단했습니다/취소" 등은 strings.xml로 이동하세요. 또한 "${data.nickname}님" 형태와 "$nickname 님" 형태가 혼재합니다(공백 유무). 하나로 통일하세요.
예시(strings.xml):
<resources>
<string name="common_yes">예</string>
<string name="common_no">아니오</string>
<string name="block_confirm_title">%1$s님을 차단하시겠습니까?</string>
<string name="block_done">%1$s님을 차단했습니다.</string>
<string name="block_cancel">차단 취소</string>
</resources>사용:
val nickname = "친구"
val textList = listOf(
getString(R.string.block_confirm_title, nickname),
getString(R.string.common_yes),
getString(R.string.common_no)
)🤖 Prompt for AI Agents
In app/src/main/java/umc/onairmate/ui/friend/list/FriendListTabFragment.kt
around lines 150 to 168, the popup strings and Toast text are hardcoded and
inconsistent (some use "$nickname 님" with a space, others use
"${data.nickname}님" without); move all user-visible literals
("예","아니오","차단했습니다","차단 취소", and the confirmation title) into strings.xml as
formatted resources (e.g., block_confirm_title="%1$s님을 차단하시겠습니까?",
block_done="%1$s님을 차단했습니다.", common_yes, common_no, block_cancel) and replace
the inline literals with getString(...) calls using the nickname as the format
arg; ensure you standardize the spacing by using the same "%1$s님" format
everywhere (no extra space) and update both the popup textList and the Toast
messages to use these string resources.
| <?xml version="1.0" encoding="utf-8"?> | ||
| <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
루트 ConstraintLayout의 height=wrap_content로 인해 RV/오버레이 제약 해석 오류 가능 — match_parent로 변경 권장
자식이 0dp(height)로 상하 제약을 사용하는 구조에서는 부모가 고정 크기여야 합니다. 현재 wrap_content면 측정이 불안정해 오버레이가 꽉 차지 않거나 RV가 0 높이로 렌더링될 수 있습니다.
다음 변경을 권장합니다:
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| android:layout_height="wrap_content" | |
| android:layout_height="match_parent" |
🤖 Prompt for AI Agents
In app/src/main/res/layout/fragment_friend_list_tab.xml around line 4, the root
ConstraintLayout currently uses android:layout_height="wrap_content", which can
cause RecyclerView/overlay constraint measurement errors when child views use
0dp with top/bottom constraints; change the root layout's height to match_parent
so the parent has a fixed size and children using 0dp can measure correctly,
keeping other constraints the same.
| <LinearLayout | ||
| android:id="@+id/layout_empty" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="match_parent" | ||
| android:orientation="vertical" | ||
| android:gravity="center" | ||
| android:background="@android:color/transparent" | ||
| app:layout_constraintTop_toTopOf="parent" | ||
| app:layout_constraintBottom_toBottomOf="parent" | ||
| app:layout_constraintStart_toStartOf="parent" | ||
| app:layout_constraintEnd_toEndOf="parent"> | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
빈 상태 오버레이가 기본 VISIBLE — 초기 화면 가림/터치 혼선 유발
layout_empty가 기본값(VISIBLE)이라 화면 진입 시 목록 유무 판단 전까지 전체를 덮습니다. 초기 플래시/깜빡임 및 뒤의 RV 클릭 혼선이 생길 수 있습니다. 기본을 GONE으로 두고, 필요 시만 VISIBLE로 토글하세요. 또한 오버레이가 보일 때 뒤의 RV 터치를 막으려면 clickable/focusable 설정이 필요합니다.
<LinearLayout
android:id="@+id/layout_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center"
- android:background="@android:color/transparent"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:background="@android:color/transparent"
+ android:visibility="gone"
+ android:clickable="true"
+ android:focusable="true"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <LinearLayout | |
| android:id="@+id/layout_empty" | |
| android:layout_width="match_parent" | |
| android:layout_height="match_parent" | |
| android:orientation="vertical" | |
| android:gravity="center" | |
| android:background="@android:color/transparent" | |
| app:layout_constraintTop_toTopOf="parent" | |
| app:layout_constraintBottom_toBottomOf="parent" | |
| app:layout_constraintStart_toStartOf="parent" | |
| app:layout_constraintEnd_toEndOf="parent"> | |
| <LinearLayout | |
| android:id="@+id/layout_empty" | |
| android:layout_width="match_parent" | |
| android:layout_height="match_parent" | |
| android:orientation="vertical" | |
| android:gravity="center" | |
| android:background="@android:color/transparent" | |
| android:visibility="gone" | |
| android:clickable="true" | |
| android:focusable="true" | |
| app:layout_constraintTop_toTopOf="parent" | |
| app:layout_constraintBottom_toBottomOf="parent" | |
| app:layout_constraintStart_toStartOf="parent" | |
| app:layout_constraintEnd_toEndOf="parent"> |
🤖 Prompt for AI Agents
In app/src/main/res/layout/fragment_friend_list_tab.xml around lines 60 to 71,
the layout_empty overlay is VISIBLE by default which covers the screen until the
list presence is determined; change its default visibility to GONE, and add
android:clickable="true" and android:focusable="true" so when you set it VISIBLE
it will block touches to the RecyclerView behind it; ensure the code that
shows/hides this view toggles visibility to VISIBLE only when the empty state is
confirmed and back to GONE when data is present.
| <ImageView | ||
| android:id="@+id/iv_empty_image" | ||
| android:layout_width="58dp" | ||
| android:layout_height="58dp" | ||
| android:layout_marginTop="66dp" | ||
| android:src="@drawable/ic_empty_room"/> | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
접근성: 빈 상태 이미지에 contentDescription 누락
장식용 이미지면 스크린리더 무시를 위해 @null을 지정하세요. 대체 텍스트가 필요한 경우 적절한 문자열 리소스를 사용하세요.
<ImageView
android:id="@+id/iv_empty_image"
android:layout_width="58dp"
android:layout_height="58dp"
android:layout_marginTop="66dp"
- android:src="@drawable/ic_empty_room"/>
+ android:src="@drawable/ic_empty_room"
+ android:contentDescription="@null"/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <ImageView | |
| android:id="@+id/iv_empty_image" | |
| android:layout_width="58dp" | |
| android:layout_height="58dp" | |
| android:layout_marginTop="66dp" | |
| android:src="@drawable/ic_empty_room"/> | |
| <ImageView | |
| android:id="@+id/iv_empty_image" | |
| android:layout_width="58dp" | |
| android:layout_height="58dp" | |
| android:layout_marginTop="66dp" | |
| android:src="@drawable/ic_empty_room" | |
| android:contentDescription="@null"/> |
🤖 Prompt for AI Agents
In app/src/main/res/layout/fragment_friend_list_tab.xml around lines 72 to 78
the ImageView for the empty state is missing a contentDescription; if the image
is purely decorative set the contentDescription attribute to the Android null
resource (i.e., @null) so screen readers ignore it, otherwise set
contentDescription to an appropriate string resource (e.g., a descriptive entry
in strings.xml) and reference that resource.
| <Button | ||
| android:id="@+id/btn_block" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:text="친구 차단"/> | ||
| </LinearLayout> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
하드코딩 문자열 사용 — 문자열 리소스로 분리하여 i18n/일관성 확보
Button 텍스트는 리소스로 관리하세요.
<Button
android:id="@+id/btn_block"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="친구 차단"/>
+ android:text="@string/friend_block"/>strings.xml에 다음을 추가하세요(파일 외 변경):
<resources>
<string name="friend_block">친구 차단</string>
</resources>🤖 Prompt for AI Agents
In app/src/main/res/layout/fragment_friend_list_tab.xml around lines 88 to 93
the Button uses a hardcoded android:text value; replace the literal text with a
string resource reference (e.g. @string/friend_block) and add the corresponding
entry named "friend_block" to your module's strings.xml resource file containing
"친구 차단" so the UI text is localized and consistent.
|
팝업창 디자인이 피그마랑 다른것 같습니다. 피그마 영상재생 팝업디자인 확인해주세요 |
|
테스트용 코드유지한채로 pr날리지 말아주세요 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🔭 Outside diff range comments (2)
app/src/main/res/layout/fragment_profile.xml (2)
26-45: 상단 아이콘 접근성 속성 누락 — contentDescription 추가 필요검색/알림 아이콘에 접근성 라벨이 없습니다. 보조기기 사용자를 위해 필수입니다. 장식용이라면
@null, 기능 버튼이라면 의미 있는 설명을 넣어주세요. strings.xml에 키 추가도 함께 부탁드립니다.<ImageView android:id="@+id/iv_search" @@ android:layout_marginEnd="16dp"/> + android:contentDescription="@string/desc_search"/> <ImageView android:id="@+id/iv_alarm" @@ android:layout_marginEnd="20dp"/> + android:contentDescription="@string/desc_notifications"/>
12-315: 하드코딩 문자열 전수정 권장(@string 리소스화)"ON AIR mate", "프로필 사진 변경", "개인정보", "나의 활동" 등 다수의 문자열이 하드코딩되어 있습니다. 다국어/접근성/일관성 측면에서 strings.xml로 이전하세요.
원하시면 본 파일의 문자열 키 목록과 strings.xml 패치를 만들어 드리겠습니다.
🧹 Nitpick comments (3)
app/src/main/res/layout/fragment_profile.xml (3)
7-9: 루트 ConstraintLayout의 marginTop은 효과 없음 — WindowInsets/paddingTop로 대체하세요루트 뷰의 margin은 부모가 없어 적용되지 않습니다. 상태바 간격 확보가 목적이라면 WindowInsets 처리나 paddingTop을 사용하세요.
적용 예(해당 범위 내 변경만 표시):
- android:layout_marginTop="20dp"
114-137: 닉네임 행: 고정 높이/left 마진/하드코딩 문자열 정리 필요
- 17dp 고정 높이는 텍스트 클리핑 위험 → wrap_content 권장.
- marginLeft 대신 marginStart 사용해 RTL 대응.
- 문자열은 @string 리소스로 이전. 값 텍스트는 코드에서 바인딩하고 레이아웃에는 플레이스홀더를 두지 않는 게 좋습니다.
- android:layout_height="17dp" + android:layout_height="wrap_content" @@ - android:text="닉네임" + android:text="@string/profile_nickname" @@ - android:layout_marginLeft="38dp" - android:text="[사용자 닉네임]" /> + android:layout_marginStart="38dp" />확인 부탁: 상기 @string 키가 없으면 추가가 필요합니다.
293-294: 개발 메모 주석은 PR에서 제거 권장“✅ 여기 수정”과 같은 작업 기록성 주석은 커밋에서 정리해 주세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
app/src/main/res/layout/fragment_profile.xml(4 hunks)
🔇 Additional comments (1)
app/src/main/res/layout/fragment_profile.xml (1)
19-23: 타이틀 폰트 지정 변경 LGTMfontFamily로의 전환 일관성 좋습니다. 스타일(Theme/TextAppearance)로 승격은 선택 사항입니다.
| android:id="@+id/layout_my_private_info" | ||
| android:layout_width="280dp" | ||
| android:layout_height="88dp" | ||
| android:layout_gravity="center" | ||
| android:orientation="vertical" | ||
| android:layout_marginTop="40dp"> | ||
|
|
||
| <TextView | ||
| android:id="@+id/tv_nickname_label" | ||
| android:layout_width="wrap_content" | ||
| <LinearLayout | ||
| android:id="@+id/layout_personal_info" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:text="닉네임" | ||
| android:textSize="14sp" | ||
| android:layout_marginStart="20dp"/> | ||
| android:orientation="horizontal"> | ||
|
|
||
| <TextView | ||
| android:id="@+id/tv_nickname_value" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:text="[사용자 닉네임]" | ||
| android:textSize="14sp" | ||
| android:layout_marginStart="30dp"/> | ||
| </LinearLayout> | ||
| <!-- 개인정보 텍스트 --> | ||
| <TextView | ||
| android:id="@+id/tv_personal_info" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="19dp" | ||
| android:fontFamily="@font/pretendard_medium" | ||
| android:text="개인정보" | ||
| android:textSize="16sp" /> | ||
|
|
||
| <!-- 인기도 영역 --> | ||
| <androidx.constraintlayout.widget.ConstraintLayout | ||
| android:id="@+id/layout_popular" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_marginTop="16dp" | ||
| android:layout_marginStart="12dp" | ||
| android:layout_marginEnd="12dp"> | ||
| <ImageView | ||
| android:layout_width="10dp" | ||
| android:layout_height="10dp" | ||
| android:layout_marginLeft="214dp" | ||
| android:src="@drawable/ic_arrow"/> | ||
| </LinearLayout> | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
고정 폭/높이 + marginLeft 기반 정렬은 취약 — 가변 레이아웃으로 전환 권장
- 280dp 고정 폭, 88dp 고정 높이는 폰 크기·다국어·글꼴 크기 확대 시 깨집니다.
- 화살표 정렬을 marginLeft 214dp로 고정하는 방식은 화면마다 틀어집니다.
- 텍스트 높이 19dp 고정은 폰트 스케일에서 클리핑 위험.
아래처럼 match_parent/ wrap_content + weight로 정렬하세요.
- android:id="@+id/layout_my_private_info"
- android:layout_width="280dp"
- android:layout_height="88dp"
+ android:id="@+id/layout_my_private_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
@@
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:paddingHorizontal="16dp">
@@
- <TextView
- android:id="@+id/tv_personal_info"
- android:layout_width="wrap_content"
- android:layout_height="19dp"
+ <TextView
+ android:id="@+id/tv_personal_info"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
android:fontFamily="@font/pretendard_medium"
android:text="개인정보"
android:textSize="16sp" />
@@
- <ImageView
- android:layout_width="10dp"
- android:layout_height="10dp"
- android:layout_marginLeft="214dp"
- android:src="@drawable/ic_arrow"/>
+ <ImageView
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:src="@drawable/ic_arrow"
+ android:contentDescription="@null"
+ android:importantForAccessibility="no"/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| android:id="@+id/layout_my_private_info" | |
| android:layout_width="280dp" | |
| android:layout_height="88dp" | |
| android:layout_gravity="center" | |
| android:orientation="vertical" | |
| android:layout_marginTop="40dp"> | |
| <TextView | |
| android:id="@+id/tv_nickname_label" | |
| android:layout_width="wrap_content" | |
| <LinearLayout | |
| android:id="@+id/layout_personal_info" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:text="닉네임" | |
| android:textSize="14sp" | |
| android:layout_marginStart="20dp"/> | |
| android:orientation="horizontal"> | |
| <TextView | |
| android:id="@+id/tv_nickname_value" | |
| android:layout_width="wrap_content" | |
| android:layout_height="wrap_content" | |
| android:text="[사용자 닉네임]" | |
| android:textSize="14sp" | |
| android:layout_marginStart="30dp"/> | |
| </LinearLayout> | |
| <!-- 개인정보 텍스트 --> | |
| <TextView | |
| android:id="@+id/tv_personal_info" | |
| android:layout_width="wrap_content" | |
| android:layout_height="19dp" | |
| android:fontFamily="@font/pretendard_medium" | |
| android:text="개인정보" | |
| android:textSize="16sp" /> | |
| <!-- 인기도 영역 --> | |
| <androidx.constraintlayout.widget.ConstraintLayout | |
| android:id="@+id/layout_popular" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:layout_marginTop="16dp" | |
| android:layout_marginStart="12dp" | |
| android:layout_marginEnd="12dp"> | |
| <ImageView | |
| android:layout_width="10dp" | |
| android:layout_height="10dp" | |
| android:layout_marginLeft="214dp" | |
| android:src="@drawable/ic_arrow"/> | |
| </LinearLayout> | |
| android:id="@+id/layout_my_private_info" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:layout_gravity="center" | |
| android:orientation="vertical" | |
| android:layout_marginTop="40dp"> | |
| <LinearLayout | |
| android:id="@+id/layout_personal_info" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:orientation="horizontal" | |
| android:gravity="center_vertical" | |
| android:paddingHorizontal="16dp"> | |
| <!-- 개인정보 텍스트 --> | |
| <TextView | |
| android:id="@+id/tv_personal_info" | |
| android:layout_width="0dp" | |
| android:layout_height="wrap_content" | |
| android:layout_weight="1" | |
| android:fontFamily="@font/pretendard_medium" | |
| android:text="개인정보" | |
| android:textSize="16sp" /> | |
| <ImageView | |
| android:layout_width="10dp" | |
| android:layout_height="10dp" | |
| android:src="@drawable/ic_arrow" | |
| android:contentDescription="@null" | |
| android:importantForAccessibility="no"/> | |
| </LinearLayout> |
| android:layout_marginLeft="214dp" | ||
| android:src="@drawable/ic_arrow"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
marginLeft 사용 → marginStart로 교체하여 RTL 대응
좌-to-우 레이아웃만 가정하지 말고 marginStart/End를 사용하세요. 일부 위치는 위의 다른 코멘트에서 함께 교정했습니다만, 남은 지점도 일괄 교체 바랍니다.
남은 marginLeft가 있는지 다음 검색으로 확인해 주세요:
Also applies to: 134-135, 158-159, 167-168, 174-175
🏁 Script executed:
rg -n "layout_marginLeft" app/src/main/res/layout/fragment_profile.xmlLength of output: 378
RTL 대응: layout_marginLeft → layout_marginStart로 일괄 교체 필요
layout_marginLeft는 RTL 환경에서 올바르게 동작하지 않으니 marginStart로 교체해주세요.
- 파일: app/src/main/res/layout/fragment_profile.xml
- 110: android:layout_marginLeft="214dp" → android:layout_marginStart="214dp"
- 134: android:layout_marginLeft="38dp" → android:layout_marginStart="38dp"
- 158: android:layout_marginLeft="38dp" → android:layout_marginStart="38dp"
- 167: android:layout_marginLeft="60dp"/> → android:layout_marginStart="60dp"/>
- 174: android:layout_marginLeft="85dp" → android:layout_marginStart="85dp"
예시(수정 후):
android:layout_marginStart="214dp"
android:src="@drawable/ic_arrow"/>
수정 후 잔여 여부 확인: rg -n "layout_marginLeft" app/src/main/res/layout/fragment_profile.xml
🤖 Prompt for AI Agents
In app/src/main/res/layout/fragment_profile.xml around lines 110–174, replace
all android:layout_marginLeft attributes with android:layout_marginStart to
support RTL: change line 110 to android:layout_marginStart="214dp", line 134 to
android:layout_marginStart="38dp", line 158 to
android:layout_marginStart="38dp", line 167 to
android:layout_marginStart="60dp"/>, and line 174 to
android:layout_marginStart="85dp"; keep the rest of each attribute and element
intact (no other formatting or value changes) and then run rg -n
"layout_marginLeft" app/src/main/res/layout/fragment_profile.xml to confirm no
occurrences remain.
| <LinearLayout | ||
| android:id="@+id/layout_popular_content" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="17dp" | ||
| android:orientation="horizontal" | ||
| android:layout_marginTop="12dp" | ||
| android:layout_marginStart="12dp" | ||
| app:layout_constraintTop_toTopOf="parent" | ||
| app:layout_constraintStart_toStartOf="parent" | ||
| app:layout_constraintBottom_toBottomOf="parent"> | ||
| android:layout_marginTop="15dp"> | ||
|
|
||
| <TextView | ||
| android:id="@+id/tv_popular" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:fontFamily="@font/pretendard_regular" | ||
| android:text="인기도" | ||
| android:textSize="14sp" | ||
| android:layout_marginEnd="12dp" /> | ||
| android:textSize="14sp" /> | ||
|
|
||
| <ImageView | ||
| android:id="@+id/iv_popularity_icon" | ||
| android:layout_width="20dp" | ||
| android:layout_height="20dp" | ||
| android:src="@drawable/ic_popular" | ||
| android:layout_marginEnd="12dp" /> | ||
| android:layout_width="14dp" | ||
| android:layout_height="14dp" | ||
| android:layout_marginLeft="38dp" | ||
| android:src="@drawable/ic_popular" /> | ||
|
|
||
| <TextView | ||
| android:id="@+id/tv_popularity_score" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:text="***점" | ||
| android:textSize="14sp" /> | ||
| </LinearLayout> | ||
| android:textSize="14sp" | ||
| android:layout_marginLeft="60dp"/> | ||
|
|
||
| <!-- 툴팁 --> | ||
| <ImageView | ||
| android:id="@+id/iv_tooltip" | ||
| android:layout_width="16dp" | ||
| android:layout_height="16dp" | ||
| android:src="@drawable/ic_question" | ||
| app:layout_constraintEnd_toEndOf="parent" | ||
| app:layout_constraintBottom_toBottomOf="@id/layout_popular_content" | ||
| android:layout_marginEnd="12dp" /> | ||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||
|
|
||
| <!-- 나의 활동 --> | ||
| <TextView | ||
| android:id="@+id/tv_my_activity" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:text="나의 활동" | ||
| android:textStyle="bold" | ||
| android:textSize="16sp" | ||
| android:layout_marginTop="16dp" | ||
| android:layout_marginStart="20dp"/> | ||
| <!-- 툴팁 --> | ||
| <ImageView | ||
| android:id="@+id/iv_tooltip" | ||
| android:layout_width="14dp" | ||
| android:layout_height="14dp" | ||
| android:layout_marginLeft="85dp" | ||
| android:src="@drawable/ic_question" /> | ||
| </LinearLayout> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
인기도 섹션: marginLeft 체이닝과 a11y 속성 보완
- 여러 marginLeft로 간격을 고정하는 방식은 화면별로 틀어집니다. 최소한 marginStart로 교체하고 간격은 작은 값으로 조정하세요.
- 아이콘/물음표는 장식용이면 contentDescription @null 지정, 중요하면 의미 있는 설명을 부여하세요.
<ImageView
android:id="@+id/iv_popularity_icon"
- android:layout_width="14dp"
- android:layout_height="14dp"
- android:layout_marginLeft="38dp"
- android:src="@drawable/ic_popular" />
+ android:layout_width="14dp"
+ android:layout_height="14dp"
+ android:layout_marginStart="16dp"
+ android:src="@drawable/ic_popular"
+ android:contentDescription="@null"
+ android:importantForAccessibility="no" />
<TextView
android:id="@+id/tv_popularity_score"
@@
- android:textSize="14sp"
- android:layout_marginLeft="60dp"/>
+ android:textSize="14sp"
+ android:layout_marginStart="8dp"/>
<!-- 툴팁 -->
<ImageView
android:id="@+id/iv_tooltip"
@@
- android:layout_marginLeft="85dp"
- android:src="@drawable/ic_question" />
+ android:layout_marginStart="8dp"
+ android:src="@drawable/ic_question"
+ android:contentDescription="@string/desc_popularity_info" />상기 @string/desc_popularity_info가 없다면 strings.xml에 추가 필요.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <LinearLayout | |
| android:id="@+id/layout_popular_content" | |
| android:layout_width="wrap_content" | |
| android:layout_height="wrap_content" | |
| android:layout_width="match_parent" | |
| android:layout_height="17dp" | |
| android:orientation="horizontal" | |
| android:layout_marginTop="12dp" | |
| android:layout_marginStart="12dp" | |
| app:layout_constraintTop_toTopOf="parent" | |
| app:layout_constraintStart_toStartOf="parent" | |
| app:layout_constraintBottom_toBottomOf="parent"> | |
| android:layout_marginTop="15dp"> | |
| <TextView | |
| android:id="@+id/tv_popular" | |
| android:layout_width="wrap_content" | |
| android:layout_height="wrap_content" | |
| android:fontFamily="@font/pretendard_regular" | |
| android:text="인기도" | |
| android:textSize="14sp" | |
| android:layout_marginEnd="12dp" /> | |
| android:textSize="14sp" /> | |
| <ImageView | |
| android:id="@+id/iv_popularity_icon" | |
| android:layout_width="20dp" | |
| android:layout_height="20dp" | |
| android:src="@drawable/ic_popular" | |
| android:layout_marginEnd="12dp" /> | |
| android:layout_width="14dp" | |
| android:layout_height="14dp" | |
| android:layout_marginLeft="38dp" | |
| android:src="@drawable/ic_popular" /> | |
| <TextView | |
| android:id="@+id/tv_popularity_score" | |
| android:layout_width="wrap_content" | |
| android:layout_height="wrap_content" | |
| android:text="***점" | |
| android:textSize="14sp" /> | |
| </LinearLayout> | |
| android:textSize="14sp" | |
| android:layout_marginLeft="60dp"/> | |
| <!-- 툴팁 --> | |
| <ImageView | |
| android:id="@+id/iv_tooltip" | |
| android:layout_width="16dp" | |
| android:layout_height="16dp" | |
| android:src="@drawable/ic_question" | |
| app:layout_constraintEnd_toEndOf="parent" | |
| app:layout_constraintBottom_toBottomOf="@id/layout_popular_content" | |
| android:layout_marginEnd="12dp" /> | |
| </androidx.constraintlayout.widget.ConstraintLayout> | |
| <!-- 나의 활동 --> | |
| <TextView | |
| android:id="@+id/tv_my_activity" | |
| android:layout_width="wrap_content" | |
| android:layout_height="wrap_content" | |
| android:text="나의 활동" | |
| android:textStyle="bold" | |
| android:textSize="16sp" | |
| android:layout_marginTop="16dp" | |
| android:layout_marginStart="20dp"/> | |
| <!-- 툴팁 --> | |
| <ImageView | |
| android:id="@+id/iv_tooltip" | |
| android:layout_width="14dp" | |
| android:layout_height="14dp" | |
| android:layout_marginLeft="85dp" | |
| android:src="@drawable/ic_question" /> | |
| </LinearLayout> | |
| <LinearLayout | |
| android:id="@+id/layout_popular_content" | |
| android:layout_width="match_parent" | |
| android:layout_height="17dp" | |
| android:orientation="horizontal" | |
| android:layout_marginTop="15dp"> | |
| <TextView | |
| android:id="@+id/tv_popular" | |
| android:layout_width="wrap_content" | |
| android:layout_height="wrap_content" | |
| android:fontFamily="@font/pretendard_regular" | |
| android:text="인기도" | |
| android:textSize="14sp" /> | |
| <ImageView | |
| android:id="@+id/iv_popularity_icon" | |
| android:layout_width="14dp" | |
| android:layout_height="14dp" | |
| android:layout_marginStart="16dp" | |
| android:src="@drawable/ic_popular" | |
| android:contentDescription="@null" | |
| android:importantForAccessibility="no" /> | |
| <TextView | |
| android:id="@+id/tv_popularity_score" | |
| android:layout_width="wrap_content" | |
| android:layout_height="wrap_content" | |
| android:text="***점" | |
| android:textSize="14sp" | |
| android:layout_marginStart="8dp"/> | |
| <!-- 툴팁 --> | |
| <ImageView | |
| android:id="@+id/iv_tooltip" | |
| android:layout_width="14dp" | |
| android:layout_height="14dp" | |
| android:layout_marginStart="8dp" | |
| android:src="@drawable/ic_question" | |
| android:contentDescription="@string/desc_popularity_info" /> | |
| </LinearLayout> |
🤖 Prompt for AI Agents
In app/src/main/res/layout/fragment_profile.xml around lines 139 to 176, replace
the chained android:layout_marginLeft attributes with start-aware attributes
(android:layout_marginStart) and reduce the fixed offsets (use smaller dp values
or rely on spacing via layout_weight or padding) so layout adapts to RTL and
varied screen sizes; ensure views use wrap_content for widths/heights where
appropriate rather than hard fixed widths like 17dp for the parent; for
accessibility, set android:contentDescription="@null" on purely decorative icons
(ic_popular or ic_question) or provide a meaningful string resource (e.g.
@string/desc_popularity_info) for important icons and add that string to
strings.xml if it does not exist.
| android:id="@+id/layout_my_active" | ||
| android:layout_width="280dp" | ||
| android:layout_height="152dp" | ||
| android:orientation="vertical" | ||
| android:layout_gravity="center" | ||
| android:layout_marginTop="40dp"> | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
나의 활동 컨테이너의 280dp/152dp 고정 크기 — 반응형/접근성 이슈
스크롤 콘텐츠 폭·높이는 가변이어야 합니다. 폰/태블릿, 글꼴 스케일에서 안정적으로 동작하도록 변경하세요.
- android:layout_width="280dp"
- android:layout_height="152dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| android:id="@+id/layout_my_active" | |
| android:layout_width="280dp" | |
| android:layout_height="152dp" | |
| android:orientation="vertical" | |
| android:layout_gravity="center" | |
| android:layout_marginTop="40dp"> | |
| android:id="@+id/layout_my_active" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:orientation="vertical" | |
| android:layout_gravity="center" | |
| android:layout_marginTop="40dp"> |
🤖 Prompt for AI Agents
app/src/main/res/layout/fragment_profile.xml lines 180-186: 현재 레이아웃이
android:layout_width="280dp" 및 android:layout_height="152dp"로 고정되어 반응형·접근성에
취약합니다; 고정 dp를 제거하고 폭은 부모에 맞추거나 제약레이아웃의 경우 0dp(match_constraint)로, 높이는 내용에 따라
wrap_content로 변경하거나 LinearLayout이면 layout_weight를 사용해 유연하게 만들고, 텍스트는 sp 단위를
사용·확장 가능하도록 하고 필요시 minHeight/maxHeight나 padding으로 레이아웃 안정성을 보장해 폰/태블릿과 글꼴 배율
모두에서 올바르게 동작하도록 수정하세요.
| <!-- 참여한 방 --> | ||
| <LinearLayout | ||
| android:id="@+id/layout_my_rooms" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="17dp" | ||
| android:orientation="horizontal" | ||
| android:gravity="center_vertical" | ||
| android:layout_marginTop="15dp"> | ||
|
|
||
| <ImageView | ||
| android:layout_width="16dp" | ||
| android:layout_height="16dp" | ||
| android:src="@drawable/ic_arrow"/> | ||
| </LinearLayout> | ||
| <TextView | ||
| android:layout_width="52dp" | ||
| android:layout_height="17dp" | ||
| android:layout_weight="1" | ||
| android:text="참여한 방" | ||
| android:textSize="14sp"/> | ||
|
|
||
| <!-- 차단 리스트 --> | ||
| <LinearLayout | ||
| android:id="@+id/layout_block" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:orientation="horizontal" | ||
| android:gravity="center_vertical" | ||
| android:padding="16dp"> | ||
| <ImageView | ||
| android:layout_width="30dp" | ||
| android:layout_height="14dp" | ||
| android:src="@drawable/ic_arrow"/> | ||
| </LinearLayout> | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
layout_weight 사용 방식 오류 — width는 0dp여야 함
LinearLayout에서 weight를 쓰려면 해당 뷰의 폭을 0dp로 해야 정상적으로 남은 공간을 분배합니다. 현재 52dp + weight는 의도대로 동작하지 않습니다. 높이 17dp도 wrap_content로.
- <TextView
- android:layout_width="52dp"
- android:layout_height="17dp"
- android:layout_weight="1"
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
android:text="참여한 방"
android:textSize="14sp"/>🤖 Prompt for AI Agents
In app/src/main/res/layout/fragment_profile.xml around lines 196 to 217, the
TextView uses layout_weight but has a fixed layout_width of 52dp and both the
LinearLayout and TextView use fixed 17dp heights; change the TextView's
layout_width to 0dp so weight can allocate remaining space and keep
layout_weight="1", set the TextView's layout_height to wrap_content, and change
the parent LinearLayout's layout_height to wrap_content (also set the
ImageView's layout_height to wrap_content) so views size correctly.
| <!-- 차단 리스트 --> | ||
| <LinearLayout | ||
| android:id="@+id/layout_block" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="17dp" | ||
| android:orientation="horizontal" | ||
| android:gravity="center_vertical" | ||
| android:layout_marginTop="15dp"> | ||
|
|
||
| <ImageView | ||
| android:layout_width="16dp" | ||
| android:layout_height="16dp" | ||
| android:src="@drawable/ic_arrow"/> | ||
| </LinearLayout> | ||
| <TextView | ||
| android:layout_width="52dp" | ||
| android:layout_height="17dp" | ||
| android:layout_weight="1" | ||
| android:text="차단 리스트" | ||
| android:textSize="14sp"/> | ||
|
|
||
| <!-- 의견 보내기 --> | ||
| <LinearLayout | ||
| android:id="@+id/layout_opinion" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:orientation="horizontal" | ||
| android:gravity="center_vertical" | ||
| android:padding="16dp"> | ||
| <ImageView | ||
| android:layout_width="30dp" | ||
| android:layout_height="14dp" | ||
| android:src="@drawable/ic_arrow"/> | ||
| </LinearLayout> | ||
|
|
||
| <TextView | ||
| android:layout_width="0dp" | ||
| <!-- 의견 보내기 --> | ||
| <LinearLayout | ||
| android:id="@+id/layout_opinion" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_weight="1" | ||
| android:text="의견 보내기" | ||
| android:textSize="14sp"/> | ||
| android:orientation="horizontal" | ||
| android:gravity="center_vertical" | ||
| android:layout_marginTop="15dp"> | ||
|
|
||
| <ImageView | ||
| android:layout_width="16dp" | ||
| android:layout_height="16dp" | ||
| android:src="@drawable/ic_arrow"/> | ||
| </LinearLayout> | ||
| <TextView | ||
| android:layout_width="52dp" | ||
| android:layout_height="17dp" | ||
| android:layout_weight="1" | ||
| android:text="의견 보내기" | ||
| android:textSize="14sp"/> | ||
|
|
||
| <!-- 좋아한 컬렉션 --> | ||
| <LinearLayout | ||
| android:id="@+id/layout_like_collection" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:orientation="horizontal" | ||
| android:gravity="center_vertical" | ||
| android:padding="16dp"> | ||
| <ImageView | ||
| android:layout_width="30dp" | ||
| android:layout_height="14dp" | ||
| android:src="@drawable/ic_arrow"/> | ||
| </LinearLayout> | ||
|
|
||
| <TextView | ||
| android:layout_width="0dp" | ||
| <!-- 좋아한 컬렉션 --> | ||
| <LinearLayout | ||
| android:id="@+id/layout_like_collection" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:layout_weight="1" | ||
| android:text="좋아한 컬렉션" | ||
| android:textSize="14sp"/> | ||
| android:orientation="horizontal" | ||
| android:gravity="center_vertical" | ||
| android:layout_marginTop="15dp"> | ||
|
|
||
| <ImageView | ||
| android:layout_width="16dp" | ||
| android:layout_height="16dp" | ||
| android:src="@drawable/ic_arrow"/> | ||
| <TextView | ||
| android:layout_width="52dp" | ||
| android:layout_height="17dp" | ||
| android:layout_weight="1" | ||
| android:text="좋아한 컬렉션" | ||
| android:textSize="14sp"/> | ||
|
|
||
| <ImageView | ||
| android:layout_width="30dp" | ||
| android:layout_height="14dp" | ||
| android:src="@drawable/ic_arrow"/> | ||
| </LinearLayout> | ||
| </LinearLayout> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
동일한 weight/고정 높이 문제 반복 — 일괄 수정 권장
차단 리스트/의견 보내기/좋아한 컬렉션 섹션의 첫 번째 TextView도 동일 이슈가 반복됩니다. 아래 패턴으로 모두 교체해주세요.
- <TextView
- android:layout_width="52dp"
- android:layout_height="17dp"
- android:layout_weight="1"
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
android:text="차단 리스트"
android:textSize="14sp"/>같은 변경을 layout_opinion, layout_like_collection에도 적용하세요.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <!-- 차단 리스트 --> | |
| <LinearLayout | |
| android:id="@+id/layout_block" | |
| android:layout_width="match_parent" | |
| android:layout_height="17dp" | |
| android:orientation="horizontal" | |
| android:gravity="center_vertical" | |
| android:layout_marginTop="15dp"> | |
| <ImageView | |
| android:layout_width="16dp" | |
| android:layout_height="16dp" | |
| android:src="@drawable/ic_arrow"/> | |
| </LinearLayout> | |
| <TextView | |
| android:layout_width="52dp" | |
| android:layout_height="17dp" | |
| android:layout_weight="1" | |
| android:text="차단 리스트" | |
| android:textSize="14sp"/> | |
| <!-- 의견 보내기 --> | |
| <LinearLayout | |
| android:id="@+id/layout_opinion" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:orientation="horizontal" | |
| android:gravity="center_vertical" | |
| android:padding="16dp"> | |
| <ImageView | |
| android:layout_width="30dp" | |
| android:layout_height="14dp" | |
| android:src="@drawable/ic_arrow"/> | |
| </LinearLayout> | |
| <TextView | |
| android:layout_width="0dp" | |
| <!-- 의견 보내기 --> | |
| <LinearLayout | |
| android:id="@+id/layout_opinion" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:layout_weight="1" | |
| android:text="의견 보내기" | |
| android:textSize="14sp"/> | |
| android:orientation="horizontal" | |
| android:gravity="center_vertical" | |
| android:layout_marginTop="15dp"> | |
| <ImageView | |
| android:layout_width="16dp" | |
| android:layout_height="16dp" | |
| android:src="@drawable/ic_arrow"/> | |
| </LinearLayout> | |
| <TextView | |
| android:layout_width="52dp" | |
| android:layout_height="17dp" | |
| android:layout_weight="1" | |
| android:text="의견 보내기" | |
| android:textSize="14sp"/> | |
| <!-- 좋아한 컬렉션 --> | |
| <LinearLayout | |
| android:id="@+id/layout_like_collection" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:orientation="horizontal" | |
| android:gravity="center_vertical" | |
| android:padding="16dp"> | |
| <ImageView | |
| android:layout_width="30dp" | |
| android:layout_height="14dp" | |
| android:src="@drawable/ic_arrow"/> | |
| </LinearLayout> | |
| <TextView | |
| android:layout_width="0dp" | |
| <!-- 좋아한 컬렉션 --> | |
| <LinearLayout | |
| android:id="@+id/layout_like_collection" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:layout_weight="1" | |
| android:text="좋아한 컬렉션" | |
| android:textSize="14sp"/> | |
| android:orientation="horizontal" | |
| android:gravity="center_vertical" | |
| android:layout_marginTop="15dp"> | |
| <ImageView | |
| android:layout_width="16dp" | |
| android:layout_height="16dp" | |
| android:src="@drawable/ic_arrow"/> | |
| <TextView | |
| android:layout_width="52dp" | |
| android:layout_height="17dp" | |
| android:layout_weight="1" | |
| android:text="좋아한 컬렉션" | |
| android:textSize="14sp"/> | |
| <ImageView | |
| android:layout_width="30dp" | |
| android:layout_height="14dp" | |
| android:src="@drawable/ic_arrow"/> | |
| </LinearLayout> | |
| </LinearLayout> | |
| <!-- 차단 리스트 --> | |
| <LinearLayout | |
| android:id="@+id/layout_block" | |
| android:layout_width="match_parent" | |
| android:layout_height="17dp" | |
| android:orientation="horizontal" | |
| android:gravity="center_vertical" | |
| android:layout_marginTop="15dp"> | |
| <TextView | |
| android:layout_width="0dp" | |
| android:layout_height="wrap_content" | |
| android:layout_weight="1" | |
| android:text="차단 리스트" | |
| android:textSize="14sp"/> | |
| <ImageView | |
| android:layout_width="30dp" | |
| android:layout_height="14dp" | |
| android:src="@drawable/ic_arrow"/> | |
| </LinearLayout> | |
| <!-- 의견 보내기 --> | |
| <LinearLayout | |
| android:id="@+id/layout_opinion" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:orientation="horizontal" | |
| android:gravity="center_vertical" | |
| android:layout_marginTop="15dp"> | |
| <TextView | |
| android:layout_width="0dp" | |
| android:layout_height="wrap_content" | |
| android:layout_weight="1" | |
| android:text="의견 보내기" | |
| android:textSize="14sp"/> | |
| <ImageView | |
| android:layout_width="30dp" | |
| android:layout_height="14dp" | |
| android:src="@drawable/ic_arrow"/> | |
| </LinearLayout> | |
| <!-- 좋아한 컬렉션 --> | |
| <LinearLayout | |
| android:id="@+id/layout_like_collection" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:orientation="horizontal" | |
| android:gravity="center_vertical" | |
| android:layout_marginTop="15dp"> | |
| <TextView | |
| android:layout_width="0dp" | |
| android:layout_height="wrap_content" | |
| android:layout_weight="1" | |
| android:text="좋아한 컬렉션" | |
| android:textSize="14sp"/> | |
| <ImageView | |
| android:layout_width="30dp" | |
| android:layout_height="14dp" | |
| android:src="@drawable/ic_arrow"/> | |
| </LinearLayout> | |
| </LinearLayout> |
🤖 Prompt for AI Agents
In app/src/main/res/layout/fragment_profile.xml around lines 218 to 283, the
three section TextViews (차단 리스트, 의견 보내기, 좋아한 컬렉션) repeat the same bug of mixing
fixed heights with layout_weight; change each TextView to use width="0dp",
layout_weight="1" and layout_height="wrap_content" (remove the fixed 17dp
height) so the weight works correctly and the label vertically sizes to content;
apply the same replacement to the TextViews inside layout_block, layout_opinion,
and layout_like_collection.
| <LinearLayout | ||
| android:id="@+id/layout_logo" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="wrap_content" | ||
| android:orientation="vertical" | ||
| android:gravity="center" | ||
| android:padding="16dp"> | ||
| android:padding="16dp" | ||
| android:layout_marginStart="16dp"> <!-- ✅ 여기 수정 --> | ||
|
|
||
| <ImageView | ||
| android:id="@+id/onairmate_bottom_logo" | ||
| android:layout_width="470dp" | ||
| android:layout_height="89.26dp" | ||
| android:src="@drawable/logo_onairmate_profile" | ||
| android:layout_gravity="center" | ||
| android:layout_marginTop="50dp"/> | ||
|
|
||
| <Button | ||
| android:id="@+id/btn_logout" | ||
| android:layout_width="wrap_content" | ||
| android:layout_height="wrap_content" | ||
| android:src="@drawable/logo_onairmate_profile" /> | ||
| android:layout_marginTop="16dp" | ||
| android:layout_marginStart="16dp" | ||
| android:layout_marginEnd="16dp" | ||
| android:background="@drawable/bg_btn_disabled" | ||
| android:backgroundTint="@color/text5" | ||
| android:text="로그아웃" | ||
| android:textColor="@color/text5" | ||
| android:textSize="14sp" | ||
| android:fontFamily="@font/pretendard_semi_bold"/> | ||
| </LinearLayout> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
하단 로고 고정 크기(470dp/89.26dp)로 화면 깨짐 위험 + 로그아웃 버튼 스타일 점검
- 로고는 화면 폭에 맞게 축소/확대되어야 합니다. adjustViewBounds/scaleType으로 대응 권장.
- 로그아웃 버튼은 커스텀 배경 + backgroundTint 조합으로 의도치 않은 색상/대비가 발생할 수 있습니다. 디자인 시스템(Material/앱 공통 스타일) 사용을 검토하고 대비(명도)도 확인해주세요.
<ImageView
android:id="@+id/onairmate_bottom_logo"
- android:layout_width="470dp"
- android:layout_height="89.26dp"
- android:src="@drawable/logo_onairmate_profile"
- android:layout_gravity="center"
- android:layout_marginTop="50dp"/>
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:adjustViewBounds="true"
+ android:scaleType="centerInside"
+ android:src="@drawable/logo_onairmate_profile"
+ android:layout_gravity="center"
+ android:layout_marginTop="50dp"/>버튼 대비/상태 확인용 체크리스트:
- 비/활성 상태 명도 대비(최소 WCAG AA) 충족?
- backgroundTint 제거 시 의도한 스타일 유지되는지?
- 가능한 경우 앱 공통 버튼 스타일로 일원화.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find files containing the target ids
rg -n --hidden -S 'onairmate_bottom_logo|btn_logout' -g 'app/**' -C3 || true
# Locate fragment_profile.xml under app and print the surrounding lines (250-340)
FILE=$(rg -n --hidden -S --files-with-matches 'onairmate_bottom_logo' -g 'app/**' || true)
if [[ -z "$FILE" ]]; then
FILE=$(rg -n --hidden -S --files-with-matches 'fragment_profile.xml' || true)
fi
echo "Located file: $FILE"
if [[ -n "$FILE" ]]; then
echo "----- fragment_profile.xml (lines 250-340) -----"
sed -n '250,340p' "$FILE" || true
echo "----- fragment_profile.xml (full file path) -----"
realpath "$FILE" || true
else
echo "fragment_profile.xml not found under app/ - listing app/layout files for inspection"
rg -n --hidden -S '<layout|fragment_profile' -g 'app/**' -C1 || true
fiLength of output: 5182
수정 필요: 하단 로고 고정 크기(470dp/89.26dp) 사용 및 로그아웃 버튼 스타일 점검
간단히: fragment_profile.xml에서 하단 로고가 고정 dp로 지정되어 있어 다양한 화면에서 레이아웃 깨짐/오버플로우가 발생할 수 있고, 로그아웃 버튼은 custom background + backgroundTint 조합으로 의도치 않은 색상 결과가 발생할 수 있습니다.
수정이 필요한 위치:
- app/src/main/res/layout/fragment_profile.xml — lines 296–313 (ImageView id="@+id/onairmate_bottom_logo" / Button id="@+id/btn_logout")
권장 변경(diff):
<ImageView
android:id="@+id/onairmate_bottom_logo"
- android:layout_width="470dp"
- android:layout_height="89.26dp"
- android:src="@drawable/logo_onairmate_profile"
- android:layout_gravity="center"
- android:layout_marginTop="50dp"/>
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:adjustViewBounds="true"
+ android:scaleType="centerInside"
+ android:src="@drawable/logo_onairmate_profile"
+ android:layout_gravity="center"
+ android:layout_marginTop="50dp"/>로그아웃 버튼 점검 체크리스트:
- 활성/비활성 상태에서 텍스트 대비(명도)가 WCAG AA 수준을 충족하는지 확인
- custom drawable(@drawable/bg_btn_disabled)와 backgroundTint 조합 제거/변경 시 의도한 외관이 유지되는지 확인
- 가능하면 MaterialButton 또는 앱 공통 버튼 스타일로 통일하여 상태별 색상/모양을 중앙 관리
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <LinearLayout | |
| android:id="@+id/layout_logo" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:orientation="vertical" | |
| android:gravity="center" | |
| android:padding="16dp"> | |
| android:padding="16dp" | |
| android:layout_marginStart="16dp"> <!-- ✅ 여기 수정 --> | |
| <ImageView | |
| android:id="@+id/onairmate_bottom_logo" | |
| android:layout_width="470dp" | |
| android:layout_height="89.26dp" | |
| android:src="@drawable/logo_onairmate_profile" | |
| android:layout_gravity="center" | |
| android:layout_marginTop="50dp"/> | |
| <Button | |
| android:id="@+id/btn_logout" | |
| android:layout_width="wrap_content" | |
| android:layout_height="wrap_content" | |
| android:src="@drawable/logo_onairmate_profile" /> | |
| android:layout_marginTop="16dp" | |
| android:layout_marginStart="16dp" | |
| android:layout_marginEnd="16dp" | |
| android:background="@drawable/bg_btn_disabled" | |
| android:backgroundTint="@color/text5" | |
| android:text="로그아웃" | |
| android:textColor="@color/text5" | |
| android:textSize="14sp" | |
| android:fontFamily="@font/pretendard_semi_bold"/> | |
| </LinearLayout> | |
| <LinearLayout | |
| android:id="@+id/layout_logo" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:orientation="vertical" | |
| android:gravity="center" | |
| android:padding="16dp" | |
| android:layout_marginStart="16dp"> <!-- ✅ 여기 수정 --> | |
| <ImageView | |
| android:id="@+id/onairmate_bottom_logo" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:adjustViewBounds="true" | |
| android:scaleType="centerInside" | |
| android:src="@drawable/logo_onairmate_profile" | |
| android:layout_gravity="center" | |
| android:layout_marginTop="50dp"/> | |
| <Button | |
| android:id="@+id/btn_logout" | |
| android:layout_width="wrap_content" | |
| android:layout_height="wrap_content" | |
| android:layout_marginTop="16dp" | |
| android:layout_marginStart="16dp" | |
| android:layout_marginEnd="16dp" | |
| android:background="@drawable/bg_btn_disabled" | |
| android:backgroundTint="@color/text5" | |
| android:text="로그아웃" | |
| android:textColor="@color/text5" | |
| android:textSize="14sp" | |
| android:fontFamily="@font/pretendard_semi_bold"/> | |
| </LinearLayout> |
🤖 Prompt for AI Agents
In app/src/main/res/layout/fragment_profile.xml around lines 286–316, the bottom
logo ImageView uses fixed dp (470dp x 89.26dp) which breaks on different screens
and the logout Button combines a custom drawable with backgroundTint causing
unpredictable colors; replace the fixed-size ImageView with responsive
attributes (e.g., use wrap_content or match_constraint/width="match_parent" with
android:adjustViewBounds="true" and an appropriate android:scaleType such as
centerCrop or fitCenter, or provide multiple drawable densities) so the logo
scales across screen sizes, and update the logout Button to use a proper
stateful background (or switch to MaterialButton/app style) and remove
conflicting backgroundTint, ensuring textColor/stateList and background drawable
provide accessible contrast for enabled/disabled states (verify WCAG AA).
ui 수정 필요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (5)
app/src/main/res/layout/dialog_block.xml (4)
8-16: 제목 문자열 하드코딩 및 닉네임 치환 미구현"[닉네임]의 신고 사유"는 strings.xml로 분리하고, 포맷 문자열로 닉네임을 주입하세요. 디자인(피그마)과도 텍스트 스타일/여백이 일치하는지 확인 필요합니다.
예시:
- strings.xml
<string name="dialog_block_title">%1$s님의 신고 사유</string>
- 코드에서 설정:
dialogBinding.tvTitle.text = context.getString(R.string.dialog_block_title, user.nickname)
18-47: 체크박스 텍스트 하드코딩 및 오타성 네이밍(cbSports)
- 모든 문자열을 strings.xml로 이동하세요.
- "스포성 채팅"은 스포일러 의미라면 id를 cbSpoiler로 정정하는 것을 권장합니다. 현재 cbSports는 혼동을 유발합니다.
예시 diff(일부):
- <CheckBox - android:id="@+id/cbSports" + <CheckBox + android:id="@+id/cbSpoiler" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="스포성 채팅"/> + android:text="@string/dialog_block_reason_spoiler"/>strings.xml 예시:
<string name="dialog_block_reason_spam">스팸, 도배</string> <string name="dialog_block_reason_spoiler">스포성 채팅</string> <string name="dialog_block_reason_abuse">욕설</string> <string name="dialog_block_reason_hate">혐오 발언</string> <string name="dialog_block_reason_bad_nickname">부적절한 닉네임 사용</string>추가로 Material 디자인을 따른다면 MaterialCheckBox(com.google.android.material.checkbox.MaterialCheckBox) 사용을 고려해 주세요.
48-55: EditText 입력 UX 보완 필요멀티라인 입력 용도라면 inputType/lines/imeOptions 등을 명시하세요(키보드 액션/개행 동작/스크롤성).
예시 diff:
- <EditText + <EditText android:id="@+id/etExtraReason" android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="추가적인 신고 사유를 작성해주세요." + android:hint="@string/dialog_block_extra_reason_hint" android:minHeight="80dp" - android:padding="10dp" - android:layout_marginTop="10dp"/> + android:padding="10dp" + android:layout_marginTop="10dp" + android:inputType="textMultiLine" + android:gravity="top|start" + android:minLines="3" + android:maxLength="500" + android:imeOptions="actionDone"/>Material 구성요소를 쓴다면 TextInputLayout + TextInputEditText 조합으로 에러 메시지/카운터 표시를 쉽게 적용할 수 있습니다.
57-62: 버튼 스타일/활성화 조건
- 버튼 텍스트도 strings.xml로 이동하세요.
- 최소 한 가지 이유 선택 또는 추가 사유 입력 전까지 제출 버튼 비활성화 UX를 권장합니다(피그마 스펙 확인).
예시 diff:
- <Button + <Button android:id="@+id/btnSubmit" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="제출" - android:layout_marginTop="16dp"/> + android:text="@string/dialog_block_submit" + android:layout_marginTop="16dp" + android:enabled="false" + style="?attr/materialButtonOutlinedStyle"/>코드에서 체크박스/입력 변화에 따라 enabled를 토글하세요.
app/src/main/java/umc/onairmate/ui/chat_room/drawer/participants/ChatRoomParticipantRVAdapter.kt (1)
40-49: PopupWindow 바깥 터치 동작 호환성isOutsideTouchable=true일 때 배경이 없으면 기기/버전에 따라 바깥 터치가 동작하지 않는 경우가 있습니다. 배경을 투명으로라도 지정하세요.
예시 diff:
val popupWindow = PopupWindow( popupBinding.root, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, true ) popupWindow.isOutsideTouchable = true popupWindow.isFocusable = true + popupWindow.setBackgroundDrawable(android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT))
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
app/src/main/java/umc/onairmate/ui/chat_room/drawer/participants/ChatRoomParticipantRVAdapter.kt(2 hunks)app/src/main/res/layout/dialog_block.xml(1 hunks)
🔇 Additional comments (1)
app/src/main/java/umc/onairmate/ui/chat_room/drawer/participants/ChatRoomParticipantRVAdapter.kt (1)
9-9: 다이얼로그 바인딩/머티리얼 다이얼로그 import 누락 안내위 수정안을 적용하려면 DialogBlockBinding/MaterialAlertDialogBuilder/Toast import가 필요합니다.
필요 import 예시:
import com.google.android.material.dialog.MaterialAlertDialogBuilder import umc.onairmate.databinding.DialogBlockBinding import android.widget.Toast
| //itemClick.clickBlock(data) | ||
| popupWindow.dismiss() | ||
|
|
||
| // 다이얼로그 뷰 inflate | ||
| val dialogView = LayoutInflater.from(anchorView.context) | ||
| .inflate(R.layout.dialog_block, null) | ||
|
|
||
| val dialog = android.app.AlertDialog.Builder(anchorView.context) | ||
| .setView(dialogView) | ||
| .create() | ||
|
|
||
| dialog.show() | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Block 클릭 시 실제 차단/신고 로직이 호출되지 않음
현재 다이얼로그만 표시되고 어떤 콜백도 호출되지 않아 기능적으로 회귀가 발생합니다. 최소한 제출 버튼에서 기존 clickBlock(data)를 호출하거나, 사유까지 전달할 새로운 콜백을 추가해야 합니다.
아래와 같이 다이얼로그 바인딩을 사용하고 제출 버튼에서 검증 후 기존 로직을 호출하도록 제안합니다. (MaterialAlertDialogBuilder 사용 권장)
- popupBinding.tvBlock.setOnClickListener {
- //itemClick.clickBlock(data)
- popupWindow.dismiss()
-
- // 다이얼로그 뷰 inflate
- val dialogView = LayoutInflater.from(anchorView.context)
- .inflate(R.layout.dialog_block, null)
-
- val dialog = android.app.AlertDialog.Builder(anchorView.context)
- .setView(dialogView)
- .create()
-
- dialog.show()
- }
+ popupBinding.tvBlock.setOnClickListener {
+ popupWindow.dismiss()
+
+ val inflater = LayoutInflater.from(anchorView.context)
+ val dialogBinding = umc.onairmate.databinding.DialogBlockBinding.inflate(inflater)
+
+ // TODO: 피그마 스펙에 맞는 스타일 적용 필요 시 theme 확인
+ val dialog = com.google.android.material.dialog.MaterialAlertDialogBuilder(anchorView.context)
+ .setView(dialogBinding.root)
+ .create()
+
+ // 제목에 닉네임 반영 (strings.xml: dialog_block_title = "%1$s님의 신고 사유")
+ runCatching {
+ dialogBinding.tvTitle.text =
+ anchorView.context.getString(umc.onairmate.R.string.dialog_block_title, data.nickname)
+ }
+
+ dialogBinding.btnSubmit.setOnClickListener {
+ val anyChecked =
+ (dialogBinding.cbSpam.isChecked
+ || dialogBinding.cbSports.isChecked
+ || dialogBinding.cbAbuse.isChecked
+ || dialogBinding.cbHate.isChecked
+ || dialogBinding.cbNickname.isChecked)
+ val hasText = !dialogBinding.etExtraReason.text.isNullOrBlank()
+
+ if (!anyChecked && !hasText) {
+ android.widget.Toast
+ .makeText(anchorView.context,
+ umc.onairmate.R.string.dialog_block_reason_required,
+ android.widget.Toast.LENGTH_SHORT)
+ .show()
+ return@setOnClickListener
+ }
+
+ // 최소한 기존 기능 유지: 제출 시 차단 실행
+ itemClick.clickBlock(data)
+ dialog.dismiss()
+ }
+
+ dialog.show()
+ }필요한 외부 import(파일 상단에 추가):
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import umc.onairmate.databinding.DialogBlockBinding
import android.widget.Toast추가 제안:
- 사유를 전달하려면 ParticipantItemClickListener에 e.g. clickBlockConfirm(data, reasons: List, extra: String) 같은 시그니처를 신설하고, 뷰모델/도메인으로 위임하는 구조가 더 바람직합니다.
🤖 Prompt for AI Agents
In
app/src/main/java/umc/onairmate/ui/chat_room/drawer/participants/ChatRoomParticipantRVAdapter.kt
around lines 76 to 88, the AlertDialog only shows but never calls the
block/report callback causing a regression; update the dialog to inflate
DialogBlockBinding (or use MaterialAlertDialogBuilder), wire the submit button
to validate inputs and call the existing clickBlock(data) (or a new
clickBlockConfirm(...) signature if you need to pass reasons/extra), then
dismiss the dialog; also add the suggested imports at the top
(MaterialAlertDialogBuilder, DialogBlockBinding, Toast) and ensure the adapter
forwards the new callback to viewModel/domain if you introduce a new listener
method.
| android:layout_width="320dp" | ||
| android:layout_height="494dp"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
고정 크기(320dp x 494dp)로 인한 화면 깨짐/키보드 가림 가능성
다양한 해상도/회전/키보드 상황에서 다이얼로그 콘텐츠가 잘리는 리스크가 큽니다. 스크롤 가능 영역으로 감싸고, 다이얼로그 콘텐츠는 wrap_content로 두는 구성이 안전합니다.
아래처럼 ScrollView + 내부 LinearLayout으로 변경을 제안합니다:
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:padding="20dp"
- android:layout_width="320dp"
- android:layout_height="494dp">
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:padding="20dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
...
-</LinearLayout>
+</LinearLayout>
+</ScrollView>
fragment_friend_list.xml 에서 button 생성 후 팝업창 뜨는 것 확인 목적으로 리사이클러뷰 재배치함 필요시 돌려놓으면 됩니다)
체크리스트
📝작업 내용
이번 PR에서 작업한 내용을 간략히 설명해주세요
fragment_friend_list.xml 에서 button 생성 후 팝업창 뜨는 것 확인 목적으로 리사이클러뷰 재배치함 필요시 돌려놓으면 됩니다)
스크린샷
작업한 화면기능의 스크린샷을 첨부해 주세요


💬리뷰 요구사항(선택)
리뷰어가 특별히 봐주었으면 하는 부분이나 함께 고민해봐야할 부분이 있다면 작성해주세요
Summary by CodeRabbit
신기능
리팩터
스타일